﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace LynxWiki.DomainModel
{
    public class AttachmentNamespace
    {
        public string Namespace { get; set; }

        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd HH:mm:ss}")]
        public DateTime CreatedOn { get; set; }
        public string Creator { get; set; }

        public List<string> DenyReadPrivsUser; //if empty then no deny; if a user or a group a match may not read or update (even if update open to all)
        public List<string> DenyReadPrivsRole; //if empty then no deny; if a user or a group a match may not read or update (even if update open to all)
        public List<string> AllowUpdatePrivsUser; //if empty then all may update (except those denied read), or may be limited to a number of users and/or groups
        public List<string> AllowUpdatePrivsRole; //if empty then all may update (except those denied read), or may be limited to a number of users and/or groups

        public AttachmentNamespace() { }

        public AttachmentNamespace(string nameSpace, string creator, DateTime createdOn,
                string denyReadUser = "", string denyReadRole = "", string allowUpdateUser = "", string allowUpdateRole = "")
        {
            if (string.IsNullOrEmpty(nameSpace)) {
                this.Namespace = "Default";
            }
            else {
                this.Namespace = nameSpace;
            }
            this.Creator = creator;
            this.CreatedOn = createdOn;

            this.DenyReadPrivsUser = new List<string>();
            if (!string.IsNullOrEmpty(denyReadUser)) {
                string[] deny = denyReadUser.Split(',');
                if (deny.Count() > 0) {
                    foreach (string d in deny) {
                        DenyReadPrivsUser.Add(d.Trim());
                    }
                }
            }

            this.DenyReadPrivsRole = new List<string>();
            if (!string.IsNullOrEmpty(denyReadRole)) {
                string[] deny = denyReadRole.Split(',');
                if (deny.Count() > 0) {
                    foreach (string d in deny) {
                        DenyReadPrivsRole.Add(d.Trim());
                    }
                }
            }

            this.AllowUpdatePrivsUser = new List<string>();
            if (!string.IsNullOrEmpty(allowUpdateUser)) {
                string[] allow = allowUpdateUser.Split(',');
                if (allow.Count() > 0) {
                    foreach (string a in allow) {
                        AllowUpdatePrivsUser.Add(a.Trim());
                    }
                }
            }

            this.AllowUpdatePrivsRole = new List<string>();
            if (!string.IsNullOrEmpty(allowUpdateRole)) {
                string[] allow = allowUpdateRole.Split(',');
                if (allow.Count() > 0) {
                    foreach (string a in allow) {
                        AllowUpdatePrivsRole.Add(a.Trim());
                    }
                }
            }


        }

        public bool UserWriteAccess(IPrincipal user)
        {
            if (user == null && (AllowUpdatePrivsUser != null || AllowUpdatePrivsRole != null)) return false;

            if (user != null && user.Identity.GetType() == typeof(System.Security.Principal.GenericIdentity)) {
                if ((DenyReadPrivsUser != null && DenyReadPrivsUser.Count > 0) ||
                        (DenyReadPrivsRole != null && DenyReadPrivsRole.Count > 0)) {
                    return false;
                }
            }

            if (AllowUpdatePrivsUser == null && AllowUpdatePrivsRole == null) return true;

            if (user != null && user.Identity.GetType() == typeof(System.Security.Principal.GenericIdentity)) {
                if ((AllowUpdatePrivsUser != null && AllowUpdatePrivsUser.Count > 0) ||
                        (AllowUpdatePrivsRole != null && AllowUpdatePrivsRole.Count > 0)) {
                    return false;
                }
                else {
                    return true;
                }
            }

            if (AllowUpdatePrivsUser != null && AllowUpdatePrivsUser.Count == 0
                && AllowUpdatePrivsRole != null && AllowUpdatePrivsRole.Count == 0) {
                return true;
            }
            if (AllowUpdatePrivsUser != null && AllowUpdatePrivsUser.Count > 0) {
                foreach (string aUser in AllowUpdatePrivsUser) {
                    if (aUser.ToLower() == user.Identity.Name.ToLower()) return true;
                }
            }
            if (AllowUpdatePrivsRole != null && AllowUpdatePrivsRole.Count > 0) {
                foreach (string aRole in AllowUpdatePrivsRole) {
                    if (user.IsInRole(aRole)) return true;
                }
            }
            return false;
        }

        public bool UserReadAccess(IPrincipal user)
        {
            if (user == null && (DenyReadPrivsUser != null || DenyReadPrivsRole != null)) return false;

            if (DenyReadPrivsUser == null && DenyReadPrivsRole == null) return true;

            if (user != null && user.Identity.GetType() == typeof(System.Security.Principal.GenericIdentity)) {
                if ((DenyReadPrivsUser != null && DenyReadPrivsUser.Count > 0) ||
                        (DenyReadPrivsRole != null && DenyReadPrivsRole.Count > 0)) {
                    return false;
                }
                else {
                    return true;
                }
            }

            if (DenyReadPrivsUser != null && DenyReadPrivsUser.Count == 0
                && DenyReadPrivsRole != null && DenyReadPrivsRole.Count == 0) {
                return true;
            }

            if (DenyReadPrivsUser != null && DenyReadPrivsUser.Count > 0) {
                foreach (string dUser in DenyReadPrivsUser) {
                    if (dUser.ToLower() == user.Identity.Name.ToLower()) return false;
                }
            }

            if (DenyReadPrivsRole != null && DenyReadPrivsRole.Count > 0) {
                foreach (string dRole in DenyReadPrivsRole) {
                    if (user.IsInRole(dRole)) return false;
                }
            }

            return true;
        }



        public AttachmentNamespace(string nameSpace, string creator)
            : this(nameSpace, creator, DateTime.Now)
        {
        }

        public AttachmentNamespace(string xml)
        {
            XDocument doc = XDocument.Parse(xml);
            AttachmentNamespace temp = (from item in doc.Descendants("attachmentNamespace")
                                  select new AttachmentNamespace {
                                      Namespace = (string)item.Element("nameSpace"),
                                      Creator = (string)item.Element("creator"),
                                      CreatedOn = (DateTime)item.Element("createdOn")
                                  }).First();
            List<string> tempDenyUser = doc.Descendants("attachmentNamespace").Elements("denyUser").Select(t => (string)t.Attribute("id")).ToList();
            List<string> tempDenyRole = doc.Descendants("attachmentNamespace").Elements("denyRole").Select(t => (string)t.Attribute("id")).ToList();
            List<string> tempAllowUser = doc.Descendants("attachmentNamespace").Elements("allowUser").Select(t => (string)t.Attribute("id")).ToList();
            List<string> tempAllowRole = doc.Descendants("attachmentNamespace").Elements("allowRole").Select(t => (string)t.Attribute("id")).ToList();
            this.Namespace = temp.Namespace;
            this.Creator = temp.Creator;
            this.CreatedOn = temp.CreatedOn;
            this.DenyReadPrivsUser = tempDenyUser;
            this.DenyReadPrivsRole = tempDenyRole;
            this.AllowUpdatePrivsUser = tempAllowUser;
            this.AllowUpdatePrivsRole = tempAllowRole;
        }



        public string ToXml(string path)
        {
            XDocument doc = new XDocument(
                new XElement("attachmentNamespace",
                    new XElement("nameSpace", Namespace),
                    new XElement("creator", Creator),
                    new XElement("createdOn", CreatedOn),
                    AllowUpdatePrivsUser.Select(allowUser => new XElement("allowUser", new XAttribute("id", allowUser))),
                    AllowUpdatePrivsRole.Select(allowRole => new XElement("allowRole", new XAttribute("id", allowRole))),
                    DenyReadPrivsUser.Select(denyUser => new XElement("denyUser", new XAttribute("id", denyUser))),
                    DenyReadPrivsRole.Select(denyRole => new XElement("denyRole", new XAttribute("id", denyRole)))
                    ));
            return doc.ToString(SaveOptions.None);
        }

    }
}
